#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author       : Abmer
# @Date         : 2019-08-06 10:10:57
# @Link         : https://gitee.com/edrik
# @Modified by  : Amber
# @Modified at  : 2019-08-31 09:57:05
# @Version      : v.0.1

import json
import logging
# import traceback

from . import context as ctx
from .script import str2bytes
from .capi.mbapi import api
from .capi.mbtypes import *
from .error import *
from .ext import (script, service)
from .oskit import pretty_print

log = logging.getLogger(__name__)


class JsonBuilder:
    """docstring for JsonBuilder"""

    def __init__(self, es):
        self.es = es
        self.jv = api.jsEmptyObject(self.es)

    def _2bytes(self, data):
        return str2bytes(data)

    def set(self, name, value):
        log.debug('set jsValue {}\t{} {}'.format(type(value), name, value))
        es = self.es
        if ('resp' == name):
            jval = api.jsStringW(es, json.dumps(value))
        else:
            jval = api.jsStringW(es, str(value))
        '''
        if isinstance(value, int):
            # jval = api.jsInt(es, INT(value))
        '''
        name = self._2bytes(name)
        api.jsSet(es, self.jv, name, jval)
        return self

    def build(self):
        return self.jv

    def ok(self, flag):
        self.set('code', flag and 'ok' or 'fail')
        return self

    def err(self):
        self.set('code', 'fail')
        return self


def json_parse(jsonstr):
    try:
        data = json.loads(jsonstr)
        return data
    except Exception as e:
        log.debug('[Warn] %s %s' % (e.__class__.__name__, e))
        return jsonstr


@service
def callback_fn(*args, **kw):
    print(args, kw)
    return kw


@service
def demo_fn_of_script(*args, **kwargs):
    print(args, *args)
    print(kwargs, **kwargs)
    # log.debug('%r %r %r %r', args, kwargs, *args, **kwargs)


@script('wke_log')
@FN(JS_VALUE, JS_EXEC_STATE, PVOID)
def wke_log(es, params):
    return JsonBuilder(es).ok(True).build()


@script('wke_invoke')
@FN(JS_VALUE, JS_EXEC_STATE, PVOID)
def wke_invoke(es, params):
    return JsonBuilder(es).ok(True).build()


@script('wke_execute')
@FN(JS_VALUE, JS_EXEC_STATE, PVOID)
def wke_execute(es, param):
    def _get_args(es):
        fname = api.jsToStringW(es, api.jsArg(es, 0))
        args_count = api.jsArgCount(es)
        log.debug('%r %r', fname, args_count)
        params = []
        for i in range(1, args_count):
            jsonstr = api.jsToStringW(es, api.jsArg(es, i))
            log.debug('[Debug] %r %r', jsonstr, type(jsonstr))
            if jsonstr:
                jsondata = json_parse(jsonstr)
                if 'undefined' != jsondata:
                    params.append(jsondata)
            else:
                break
        return fname, params

    def _run_py(fname, *args):
        # TODO
        pyfn = ctx.get_ioc(fname)
        log.debug('[Callback] %r %r %r', fname, pyfn, args)
        if not pyfn:
            msg = '[Script] Not function defined: %s' % fname
            # ex = ScriptError(msg)
            log.exception(msg)
            return msg, False
        try:
            return pyfn(*args), True
        except Exception as e:
            log.exception(e)
            # traceback.print_exc()
            # traceback.print_tb(e.__traceback__)
            # print(traceback.format_ext())
            return False, False

    fname, params = _get_args(es)
    data, ok = _run_py(fname, *params)
    log.debug('[Callback] return %r', data)
    '''
    builder = JsonBuilder(es).ok(ok)
    builder.set('data', data)
    if isinstance(data, dict):
        [builder.set(k, v) for k, v in data.items()]
    else:
        builder.set('data', data)
    '''
    return JsonBuilder(es).ok(ok).set('resp', data).build()


@script("js_msgbox")
@FN(JS_VALUE, JS_EXEC_STATE, PVOID)
def js_msgbox(es, param):
    name = api.jsToStringW(es, api.jsArg(es, 0))
    age = api.jsToInt(es, api.jsArg(es, 1))
    height = api.jsToDouble(es, api.jsArg(es, 2))
    gender = api.jsToStringW(es, api.jsArg(es, 3))
    occupation = api.jsToStringW(es, api.jsArg(es, 4))

    head = ['name', 'age', 'height', 'gender', 'occupation']
    body = [[name, age, height, gender, occupation]]
    pretty_print(head, body)
    return JsonBuilder(es).set('name', name).set('age', age).set('height', height).set('occupation', occupation).build()


@script('js_func_demo')
@FN(JS_VALUE, JS_EXEC_STATE, PVOID)
def js_func_demo(es, param):
    from .context import GlobalKV as gl
    jv = api.jsArg(es, 0)
    param = api.jsToTempStringW(es, jv)
    log.debug('callback_fn, params: %r', param)

    # #########################################################
    # jsCallGlobal()
    # call global function: jsfunc_hello
    func = api.jsStringW(es, 'jsfunc_hello')
    args = api.jsEmptyObject(es)
    # pargs = ctypes.pointer(args)
    pargs = P_JS_VALUE
    pargs.value = args
    pargs = None
    # pargs.value=args
    log.debug(">< %r %r", es, gl.exstate)
    gl_es = gl.exstate
    jv = api.jsCallGlobal(gl_es, func, pargs, 1)
    js = api.jsToTempStringW(gl_es, jv)
    log.debug(js)

    # #########################################################
    # jsCall()
    from . import script
    script.run_js('console.log("runJS: console.log(***)")')
    script.js_set_global(b'call_pyx', lambda x: log.debug(x))

    return JsonBuilder(es).set('name', 'name-abc').set("code", 1234).set('param', param).set('paramx', 12.12).build()
